﻿Imports System.ComponentModel
Imports System.Text.RegularExpressions
Imports System.Text

Namespace Controls
    Public Class ctlSearchTFS
        Private m_bAscending As Boolean = True
        Private m_iCurrentColumn As Integer
        Private ReadOnly m_oIconCache As New Dictionary(Of String, Integer)()

        Enum ProjectsColumnPosition
            ItemName
            ItemPath
            Type
            ProjectName
        End Enum

        Private Sub ctlSearchTFS_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Try
                cbItemType.SelectedIndex = 0

                m_oIconImageList.Images.Clear()
                m_oIconImageList.Images.Add(openContainingDirectoryToolStripMenuItem.Image)

                Dim oServers As List(Of TFSServer) = TfsApi.GetRegisteredServers()

                For Each oServer As TFSServer In oServers
                    cbServers.Items.Add(oServer)
                Next

                ' Sort the list
                cbServers.Sorted = True
                ' Now remove the sorting
                cbServers.Sorted = False
                ' Add in the empty item
                cbServers.Items.Insert(0, String.Empty)
                cbServers.SelectedIndex = 0

                Show()

                ' Set any default values
                If (Not String.IsNullOrWhiteSpace(My.Settings.SearchTFSServer)) Then
                    For iPos = 0 To cbServers.Items.Count
                        If (String.Compare(My.Settings.SearchTFSServer, Convert.ToString(cbServers.Items(iPos)), True) = 0) Then
                            cbServers.SelectedItem = cbServers.Items(iPos)
                            Exit For
                        End If
                    Next

                    If (cbCollections.Enabled) AndAlso (Not String.IsNullOrWhiteSpace(My.Settings.SearchTFSCollection)) Then
                        For iPos = 0 To cbCollections.Items.Count
                            If (String.Compare(My.Settings.SearchTFSCollection, Convert.ToString(cbCollections.Items(iPos)), True) = 0) Then
                                cbCollections.SelectedItem = cbCollections.Items(iPos)
                                Exit For
                            End If
                        Next
                    End If

                    If (cbProjects.Enabled) AndAlso (Not String.IsNullOrWhiteSpace(My.Settings.SearchTFSProject)) Then
                        For iPos = 0 To cbProjects.Items.Count
                            If (String.Compare(My.Settings.SearchTFSProject, Convert.ToString(cbProjects.Items(iPos)), True) = 0) Then
                                cbProjects.SelectedItem = cbProjects.Items(iPos)
                                Exit For
                            End If
                        Next
                    End If
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Loading Search TFS Control")
            End Try
        End Sub

        Private Sub pbDefault_Click(sender As Object, e As EventArgs) Handles pbDefault.Click
            Try
                SetStatus("Setting defaults...")

                If (cbServers.SelectedItem IsNot Nothing) Then
                    My.Settings.SearchTFSServer = cbServers.SelectedItem.ToString()
                Else
                    My.Settings.SearchTFSServer = String.Empty
                End If

                If (cbCollections.SelectedItem IsNot Nothing) Then
                    My.Settings.SearchTFSCollection = cbCollections.SelectedItem.ToString()
                Else
                    My.Settings.SearchTFSCollection = String.Empty
                End If

                If (cbProjects.SelectedItem IsNot Nothing) Then
                    My.Settings.SearchTFSProject = cbProjects.SelectedItem.ToString()
                Else
                    My.Settings.SearchTFSProject = String.Empty
                End If

                My.Settings.Save()
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Setting Defaults For Search TFS Control")
            Finally
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub cbServers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbServers.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading server information...")
                lstSearchResults.Items.Clear()
                cbCollections.Items.Clear()
                cbCollections.Enabled = False
                cbProjects.Items.Clear()
                cbProjects.Enabled = False

                If (String.IsNullOrWhiteSpace(cbServers.SelectedItem.ToString())) Then Return

                Dim oServer As TFSServer = DirectCast(cbServers.SelectedItem, TFSServer)

                Dim clcCollections As List(Of TFSCollection) = TfsApi.GetTeamProjectCollections(oServer)

                If (clcCollections.Count = 1) AndAlso (clcCollections(0).PlaceHolder) Then 'this is a legacy server - tfs08 or older
                    cbCollections.Enabled = False
                    ' This is a TFS08 or older instance so bypass collection and go directly to projects
                    cbCollections.Items.Add(clcCollections(0))
                    cbCollections.SelectedItem = 0
                    cbCollections_SelectedIndexChanged(sender, e)
                Else 'assume this is TFS2010 or newer
                    For Each oCollection As TFSCollection In clcCollections
                        cbCollections.Items.Add(oCollection)
                    Next

                    cbCollections.Enabled = (cbCollections.Items.Count > 0)

                    ' Insert after setting enabled
                    cbCollections.Items.Insert(0, String.Empty)
                End If
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Collections For Search TFS Control")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Sub cbCollections_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbCollections.SelectedIndexChanged
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                SetStatus("Loading team projects...")
                lstSearchResults.Items.Clear()
                cbProjects.Items.Clear()
                cbProjects.Enabled = False

                If (cbCollections.SelectedItem IsNot Nothing) AndAlso (String.IsNullOrWhiteSpace(cbCollections.SelectedItem.ToString())) Then Return

                Dim oCollection As TFSCollection = GetCollection()

                Dim clcProjects As List(Of TFSProject) = TfsApi.GetTeamProjects(oCollection, True)

                For Each oProject As TFSProject In clcProjects
                    cbProjects.Items.Add(oProject)
                Next

                ' If we don't already have an item, default to ALL
                If (cbProjects.SelectedIndex < 0) Then cbProjects.SelectedIndex = 0

                cbProjects.Enabled = (cbProjects.Items.Count > 0)
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Projects For Search TFS Control")
            Finally
                Cursor.Current = oCursor
                SetStatus("Ready")
            End Try
        End Sub

        Private Function GetCollection() As TFSCollection
            If (cbCollections.Enabled) Then Return DirectCast(cbCollections.SelectedItem, TFSCollection)

            ' This is a TFS08 or older instance so bypass collection and go directly to projects
            Return DirectCast(cbCollections.Items(0), TFSCollection)
        End Function

        Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim szSearchText As String = txtSearchText.Text.Trim()

                If (String.IsNullOrWhiteSpace(szSearchText)) Then Return

                SetStatus("Starting Search...")

                lstSearchResults.Items.Clear()
                m_oIconCache.Clear()
                m_oIconImageList.Images.Clear()
                m_oIconImageList.Images.Add(openContainingDirectoryToolStripMenuItem.Image)

                Dim eItemType As TFSItemType = TFSItemType.Any

                If (Not cbItemType.SelectedItem.ToString().Equals("All")) Then
                    If Not [Enum].TryParse(Of TFSItemType)(cbItemType.SelectedItem.ToString(), eItemType) Then
                        ' the parsing failed
                        eItemType = TFSItemType.Any
                    End If
                End If

                Dim oCollection As TFSCollection = GetCollection()
                Dim oProject As TFSProject = cbProjects.SelectedItem

                Dim dtStart As DateTime = DateTime.Now

                Dim clcItems As List(Of TFSItem) = TfsApi.SearchForItems(oCollection, oProject, eItemType, szSearchText)

                For Each oItem As TFSItem In clcItems
                    Dim oRootItem As ListViewItem = New ListViewItem()
                    oRootItem.Text = oItem.Name
                    oRootItem.Tag = oItem.Name
                    If (oItem.ItemType = TFSItemType.File) Then
                        Try
                            oRootItem.ImageIndex = GetIconIndex(Path.GetExtension(oItem.Name))
                        Catch
                            ' If we have problem getting the icon, we'd rather just show it without one than not at all
                        End Try
                    Else
                        ' The icon for a folder was added as the first item in the load method of the control
                        oRootItem.ImageIndex = 0
                    End If
                    'oRootItem.StateImageIndex = oRootItem.ImageIndex

                    oRootItem.SubItems.Add(New ListViewItem.ListViewSubItem(oRootItem, oItem.ServerPath))
                    oRootItem.SubItems.Add(New ListViewItem.ListViewSubItem(oRootItem, oItem.ItemType.ToString()))
                    oRootItem.SubItems.Add(New ListViewItem.ListViewSubItem(oRootItem, oItem.TeamProjectName))

                    lstSearchResults.Items.Add(oRootItem)
                Next

                If (lstSearchResults.Items.Count > 0) Then
                    lstSearchResults.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
                    lstSearchResults.SmallImageList = m_oIconImageList
                Else
                    lstSearchResults.SmallImageList = Nothing
                    Dim oListItem As New ListViewItem()
                    oListItem.Text = "No search results found."
                    oListItem.SubItems.Add(String.Empty)
                    lstSearchResults.Items.Add(oListItem)
                End If

                SetStatus(String.Format("Result count: {0} [{1} seconds]", lstSearchResults.Items.Count, (DateTime.Now - dtStart).TotalSeconds))
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Searching TFS")
                SetStatus("Exception Occurred")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub SetStatus(ByVal szMessage As String)
            lblStatus.Text = szMessage.Trim()

            ' Do not want DoEvents to alter the cursor, so always set it back
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Application.DoEvents()
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub cbProjects_EnabledChanged(sender As Object, e As EventArgs) Handles cbProjects.EnabledChanged
            Try
                btnSearch.Enabled = cbProjects.Enabled
            Catch
            End Try
        End Sub

        Private Sub txtFilter_KeyUp(sender As Object, e As KeyEventArgs) Handles txtFilter.KeyUp
            Try
                If (e.KeyCode = Keys.Escape) Then
                    txtFilter.Clear()
                End If
            Catch
            End Try
        End Sub

        Private Sub txtFilter_TextChanged(sender As Object, e As EventArgs) Handles txtFilter.TextChanged
            Try
                Dim szFilter As String = txtFilter.Text.Trim()
                If (lstSearchResults.Items.Count > 0) And (szFilter.Length >= 3) Then
                    lstSearchResults.SelectedItems.Clear()
                    For Each oItem As ListViewItem In lstSearchResults.Items
                        If (oItem.SubItems(1).Text.IndexOf(szFilter, StringComparison.OrdinalIgnoreCase) >= 0) Then
                            oItem.ForeColor = Color.Red
                            oItem.Checked = True
                        Else
                            oItem.Checked = False
                        End If
                    Next
                ElseIf (txtFilter.Text.Length = 0) Then
                    For Each oItem As ListViewItem In lstSearchResults.Items
                        oItem.Checked = False
                    Next
                End If
            Catch
            End Try
        End Sub

        Private Sub lstSearchResults_ItemChecked(sender As Object, e As ItemCheckedEventArgs) Handles lstSearchResults.ItemChecked
            Try
                If (e.Item.Checked = True) Then
                    e.Item.ForeColor = Color.Red
                Else
                    e.Item.ForeColor = lstSearchResults.ForeColor
                End If
            Catch
            End Try
        End Sub

        Private Sub txtSearchText_KeyUp(sender As Object, e As KeyEventArgs) Handles txtSearchText.KeyUp
            Try
                If (e.KeyCode = Keys.Enter) Then
                    btnSearch_Click(sender, e)
                End If
            Catch
            End Try
        End Sub

        Private Function GetIconIndex(ByVal fileExtension As String) As Integer
            Dim iNum As Integer
            Dim szExtension As String = fileExtension
            If szExtension(0) <> "."c Then
                szExtension = "."c + szExtension
            End If
            If m_oIconCache.ContainsKey(szExtension) Then
                Return m_oIconCache(szExtension)
            End If
            AddExtensionIcon(szExtension)
            iNum = m_oIconImageList.Images.Count - 1
            m_oIconCache.Add(szExtension, iNum)
            Return iNum
        End Function

        Private Sub AddExtensionIcon(ByVal fileExtension As String)
            Try
                Dim oAssociatedIcon As Icon = Nothing
                Try
                    oAssociatedIcon = Interop.IconFromExtension(fileExtension, IconSize.Small)
                Catch
                End Try
                If oAssociatedIcon IsNot Nothing Then
                    Dim oImage As Bitmap = oAssociatedIcon.ToBitmap()
                    Dim oBitmap2 As New Bitmap(&H12, &H10)
                    Graphics.FromImage(oBitmap2).DrawImageUnscaled(oImage, New Point(2, 0))
                    m_oIconImageList.Images.Add(oBitmap2)
                End If
            Catch
            End Try
        End Sub

        Private Sub GetLatestVersions()
            Dim oCollection As TFSCollection = GetCollection()

            For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                Dim szServerPath As String = oItem.SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text

                Dim eItemType As TFSItemType = TFSItemType.Any

                If Not [Enum].TryParse(Of TFSItemType)(oItem.SubItems(CInt(ProjectsColumnPosition.Type)).Text, eItemType) Then
                    ' the parsing failed
                    eItemType = TFSItemType.Any
                End If

                Dim szLocalFilePath As String = TfsApi.GetLocalPath(oCollection.CollectionUri, szServerPath)

                If (eItemType = TFSItemType.File) Then
                    Dim oInfo As New FileInfo(szLocalFilePath)

                    Dim clcExtenstions As List(Of String) = Helper.GetTFSExtensionsToTreatAsDirectory()
                    If (clcExtenstions.Count = 0) OrElse (Not clcExtenstions.Contains(oInfo.Extension.ToUpper().TrimStart("."c))) Then
                        Helper.GetLastestFromSourceControlDirectory(oInfo.Directory.FullName, oInfo.Name)
                    Else
                        ' We want this extension to be treated as if the directory itself was selected
                        Helper.GetLastestFromSourceControlDirectory(oInfo.Directory.FullName, String.Empty)
                    End If
                Else
                    Helper.GetLastestFromSourceControlDirectory(szLocalFilePath, String.Empty)
                End If
            Next
        End Sub

        Private Sub OpenContainingDirectories()
            Dim oCollection As TFSCollection = GetCollection()

            For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                Dim szServerPath As String = oItem.SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text

                Dim eItemType As TFSItemType = TFSItemType.Any

                If Not [Enum].TryParse(Of TFSItemType)(oItem.SubItems(CInt(ProjectsColumnPosition.Type)).Text, eItemType) Then
                    ' the parsing failed
                    eItemType = TFSItemType.Any
                End If

                Dim szLocalFilePath As String = TfsApi.GetLocalPath(oCollection.CollectionUri, szServerPath)

                If (eItemType = TFSItemType.File) Then
                    Dim oInfo As New FileInfo(szLocalFilePath)
                    Helper.OpenDirectory(oInfo.Directory.FullName)
                Else
                    Helper.OpenDirectory(szLocalFilePath)
                End If
            Next
        End Sub

        Private Sub OpenProjects()
            Dim oCollection As TFSCollection = GetCollection()
            For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                Dim szServerPath As String = oItem.SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text

                Dim eItemType As TFSItemType = TFSItemType.Any

                If Not [Enum].TryParse(Of TFSItemType)(oItem.SubItems(CInt(ProjectsColumnPosition.Type)).Text, eItemType) Then
                    ' the parsing failed
                    eItemType = TFSItemType.Any
                End If

                Dim szLocalFilePath As String = TfsApi.GetLocalPath(oCollection.CollectionUri, szServerPath)

                If (eItemType = TFSItemType.File) Then
                    Helper.OpenFile(szLocalFilePath)
                Else
                    Helper.OpenDirectory(szLocalFilePath)
                End If
            Next
        End Sub

        Friend Function GetTFSItemProperties(ByVal serverPath As String, ByVal itemType As TFSItemType) As TFSArtifactInfoCollection
            Const SERVER_INFO_TEXT As String = "Server information:"

            Dim clcArtifactInfoSets As TFSArtifactInfoCollection = New TFSArtifactInfoCollection()
            Dim szTFPath As String = Helper.GetPathToTFExe()

            Dim oCollection As TFSCollection = GetCollection()

            Dim szParam As String = String.Empty
            If (itemType = TFSItemType.Folder) Then szParam = "/recursive"

            Using oProcess = New Process()
                Dim oProcessStartInfo As New ProcessStartInfo(szTFPath)
                oProcessStartInfo.CreateNoWindow = True
                oProcessStartInfo.UseShellExecute = False
                oProcessStartInfo.Arguments = String.Format("properties /collection:""{1}"" ""{0}"" {2}", serverPath, oCollection.CollectionUri.ToString(), szParam)
                oProcessStartInfo.ErrorDialog = False
                oProcessStartInfo.RedirectStandardOutput = True
                oProcessStartInfo.RedirectStandardError = True
                oProcessStartInfo.RedirectStandardInput = False
                oProcessStartInfo.WorkingDirectory = Path.GetDirectoryName(szTFPath)
                oProcess.StartInfo = oProcessStartInfo
                oProcess.Start()

                ' Do not wait for the child process to exit before reading to the end of its redirected stream.
                ' Read the output stream first and then wait. This avoids a deadlock condition. 
                Dim szStandardOutput As String = oProcess.StandardOutput.ReadToEnd()
                Dim szStandardError As String = oProcess.StandardError.ReadToEnd()
                oProcess.WaitForExit()
                If oProcess.ExitCode <> 0 Then
                    Throw _
                        New ApplicationException(
                            String.Format("Error getting properties from source control. Exit Code: '{3}' Path: '{4}'{0}{0}Error text:{0}{1}{0}{0}Additional Text:{0}{2}",
                                          Environment.NewLine, szStandardError, szStandardOutput, oProcess.ExitCode, serverPath))
                End If

                Dim aszOutput As String() = szStandardOutput.Split({"Local information"}, StringSplitOptions.RemoveEmptyEntries)
                For Each szOutput As String In aszOutput
                    Dim iIndex As Integer = szOutput.LastIndexOf(SERVER_INFO_TEXT)

                    If (iIndex > 0) Then
                        Dim szServerInformation As String = szOutput.Substring(szOutput.LastIndexOf(SERVER_INFO_TEXT) + SERVER_INFO_TEXT.Length)
                        Dim clcProperties As List(Of TFSArtifactInfo) = New List(Of TFSArtifactInfo)()

                        Dim oMatches As MatchCollection = Regex.Matches(szServerInformation, "[\s]*(?<Name>[^:]*)[\s]*:(?<Value>.*)",
                                                                        RegexOptions.IgnoreCase Or RegexOptions.Multiline Or RegexOptions.IgnorePatternWhitespace)
                        For Each oMatch As Match In oMatches
                            If (Not oMatch.Success) Then Continue For
                            clcProperties.Add(New TFSArtifactInfo(oMatch.Groups("Name").Value.Trim(), oMatch.Groups("Value").Value.Trim()))
                        Next

                        clcArtifactInfoSets.Add(clcProperties)
                    End If
                Next
            End Using

            Return clcArtifactInfoSets
        End Function

#Region "Context Menu Event Handlers"

        Private Sub ContextMenuStripProjects_Opening(sender As Object, e As CancelEventArgs) Handles ContextMenuStripProjects.Opening
            Try
                openSourceControlToolStripMenuItem.Visible = False
                openCodeFiletoolStripMenuItem.Visible = False

                Dim oParent As frmMain = ParentForm
                If (Not oParent.IsSearchTFSTabSelected) Or (lstSearchResults.SelectedItems.Count = 0) Then
                    e.Cancel = True
                    Exit Sub
                End If

                ViewPropertiesToolStripMenuItem.Visible = (lstSearchResults.SelectedItems.Count = 1)
                If (lstSearchResults.SelectedItems.Count > 1) AndAlso (lstSearchResults.SelectedItems.Count <= 10) Then
                    Dim bMakeVisible As Boolean = True
                    For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                        Dim eItemType As TFSItemType = TFSItemType.Folder

                        If Not [Enum].TryParse(Of TFSItemType)(oItem.SubItems(CInt(ProjectsColumnPosition.Type)).Text, eItemType) Then
                            ' the parsing failed
                            eItemType = TFSItemType.Folder
                        End If

                        ' Properties can only be shown on one folder at a time since they are recursive
                        If (eItemType = TFSItemType.Folder) Then
                            bMakeVisible = False
                            Exit For
                        End If
                    Next

                    ViewPropertiesToolStripMenuItem.Visible = bMakeVisible
                End If

                openCodeFiletoolStripMenuItem.Visible = File.Exists(My.Settings.TextEditorPath)

                RemoveHandler openCodeFiletoolStripMenuItem.MouseDown, AddressOf openCodeFiletoolStripMenuItem_MouseDown
                openCodeFiletoolStripMenuItem.DropDownItems.Clear()

                If (openCodeFiletoolStripMenuItem.Available) Then
                    'Dim szServerPath As String = lstSearchResults.SelectedItems(0).SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text
                    Dim eItemType As TFSItemType = TFSItemType.Any

                    If Not [Enum].TryParse(Of TFSItemType)(lstSearchResults.SelectedItems(0).SubItems(CInt(ProjectsColumnPosition.Type)).Text, eItemType) Then
                        ' the parsing failed
                        eItemType = TFSItemType.Any
                    End If

                    'Dim oCollection As TFSCollection = GetCollection()
                    'Dim szLocalFilePath As String = GetLocalPath(oCollection.CollectionUri, szServerPath)

                    If (eItemType = TFSItemType.File) Then
                        openCodeFiletoolStripMenuItem.Tag = lstSearchResults.SelectedItems(0).SubItems(ProjectsColumnPosition.ItemPath).Text
                        AddHandler openCodeFiletoolStripMenuItem.MouseDown, AddressOf openCodeFiletoolStripMenuItem_MouseDown
                    Else
                        openCodeFiletoolStripMenuItem.Tag = String.Empty
                        openCodeFiletoolStripMenuItem.DropDownItems.Add("Placeholder")
                    End If
                End If
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception opening context menu")
            End Try
        End Sub

        Private Sub OpenProjectsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenProjectsToolStripMenuItem.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If (oParent.IsSearchTFSTabSelected And (lstSearchResults.SelectedItems.Count > 0)) Then
                    OpenProjects()

                    oParent.CloseIfNoShift()
                End If
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Opening Selected Project(s)")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub openContainingDirectoryToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles openContainingDirectoryToolStripMenuItem.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If (oParent.IsSearchTFSTabSelected And (lstSearchResults.SelectedItems.Count > 0)) Then
                    OpenContainingDirectories()
                    oParent.CloseIfNoShift()
                End If
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Opening Containing Directory")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub getLatestVersionOpenProjectsToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles getLatestVersionOpenProjectsToolStripMenuItem.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If oParent.IsSearchTFSTabSelected AndAlso (lstSearchResults.SelectedItems.Count > 0) Then
                    GetLatestVersions()
                    OpenProjects()
                    oParent.CloseIfNoShift()
                End If

            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Latest Version")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub getLatestVersionOpenContainingDirectoryToolStripMenuItem1_Click(sender As Object, e As EventArgs) _
            Handles getLatestVersionOpenContainingDirectoryToolStripMenuItem1.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If oParent.IsSearchTFSTabSelected AndAlso (lstSearchResults.SelectedItems.Count > 0) Then
                    GetLatestVersions()
                    OpenContainingDirectories()
                    oParent.CloseIfNoShift()
                End If

            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Latest Vesion")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub CopyToClipboard(sender As Object, e As EventArgs) _
            Handles copyToFileNameToolStripMenuItem.Click, copyToFilePathToolStripMenuItem.Click, copyToFilePathNameToolStripMenuItem.Click,
                    copyToFileNameWithoutExtentionToolStripMenuItem.Click, copyToServerPathToolStripMenuItem.Click, copyToServerPathNameToolStripMenuItem.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If oParent.IsSearchTFSTabSelected AndAlso (lstSearchResults.SelectedItems.Count > 0) Then
                    Dim oTextSB As New StringBuilder()
                    For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                        Dim szItemPath As String = oItem.SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text

                        If copyToFileNameToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szItemPath, MRUFileInfo.FileNameExtension))
                        ElseIf copyToFileNameWithoutExtentionToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szItemPath, MRUFileInfo.FileName))
                        ElseIf copyToFilePathNameToolStripMenuItem.Equals(sender) Then
                            Dim oCollection As TFSCollection = GetCollection()
                            Dim szLocalPath As String = TfsApi.GetLocalPath(oCollection.CollectionUri, szItemPath)
                            oTextSB.AppendLine(szLocalPath)
                        ElseIf copyToFilePathToolStripMenuItem.Equals(sender) Then
                            Dim oCollection As TFSCollection = GetCollection()
                            Dim szLocalPath As String = TfsApi.GetLocalPath(oCollection.CollectionUri, szItemPath)
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szLocalPath, MRUFileInfo.Path))
                        ElseIf copyToServerPathToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(MRUFiles.GetFileInfo(szItemPath, MRUFileInfo.Path)).Replace("\"c, "/"c)
                        ElseIf copyToServerPathNameToolStripMenuItem.Equals(sender) Then
                            oTextSB.AppendLine(szItemPath)
                        End If
                    Next

                    If oTextSB.Length > 0 Then
                        Clipboard.SetText(oTextSB.ToString())
                    End If
                End If

                'oParent.CloseIfNoShift()
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Copying Data To Clipboard")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub ViewPropertiesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ViewPropertiesToolStripMenuItem.Click
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm
                If oParent.IsSearchTFSTabSelected AndAlso (lstSearchResults.SelectedItems.Count <> 0) Then
                    ' a previous restriction will have limited this down to one for now
                    Dim oCollection As TFSCollection = GetCollection()
                    Dim clcArtifactInfoSets As TFSArtifactInfoCollection = New TFSArtifactInfoCollection()

                    For Each oItem As ListViewItem In lstSearchResults.SelectedItems
                        Dim szServerPath As String = oItem.SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text
                        Dim szItemType As String = oItem.SubItems(CInt(ProjectsColumnPosition.Type)).Text
                        Dim clcCurrentInfoSet As TFSArtifactInfoCollection = GetTFSItemProperties(szServerPath, [Enum].Parse(GetType(TFSItemType), szItemType))

                        ' Only pull the other properties if it is TFS2010 or newer
                        Dim clcProperties As List(Of TFSArtifactInfo) = clcCurrentInfoSet(0)
                        If (clcProperties IsNot Nothing) AndAlso (Not oCollection.PlaceHolder) Then _
                            clcProperties.AddRange(TfsApi.GetVersionedItemProperties(oCollection.CollectionUri, szServerPath))

                        ' Now add this item to set holding all items
                        clcArtifactInfoSets.Merge(clcCurrentInfoSet)
                    Next

                    Using frmProp As frmDisplayProperties = New frmDisplayProperties(clcArtifactInfoSets)
                        frmProp.ShowDialog(ParentForm)
                    End Using
                End If
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Getting Item Properties")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub openCodeFiletoolStripMenuItem_MouseDown(sender As Object, e As MouseEventArgs) Handles openCodeFiletoolStripMenuItem.MouseDown
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm

                If (Not oParent.IsSearchTFSTabSelected) Or (lstSearchResults.SelectedItems.Count <> 1) Then Exit Sub

                Dim oFileSenderMenuItem As ToolStripMenuItem = TryCast(sender, ToolStripMenuItem)
                If oFileSenderMenuItem IsNot Nothing Then
                    Dim szServerPath As String = oFileSenderMenuItem.Tag.ToString()

                    If (String.IsNullOrWhiteSpace(szServerPath)) Then Return

                    Dim szFileName As String = Path.GetFileName(szServerPath)

                    If e.Button = MouseButtons.Left Then
                        If (Not String.IsNullOrWhiteSpace(szFileName)) Then
                            ' This is a file
                            Dim szDataDirectory As String = Helper.GetDataDirectory()
                            Dim szOutputFile As String = Path.Combine(szDataDirectory, szFileName)
                            File.WriteAllText(szOutputFile, TfsApi.GetItemData(GetCollection().CollectionUri, szServerPath))

                            Using oProcess As New Process()
                                oProcess.StartInfo = New ProcessStartInfo(My.Settings.TextEditorPath)
                                oProcess.StartInfo.Arguments = szOutputFile
                                oProcess.Start()
                                oParent.CloseIfNoShift()
                            End Using
                        Else
                            ' this is a directory
                            oFileSenderMenuItem.DropDownItems(0).Visible = True
                        End If
                        'ElseIf e.Button = MouseButtons.Right Then
                        '    If String.IsNullOrWhiteSpace(szFileName) Then
                        '        ' this is a directory
                        '        using oProcess As New Process()
                        '           oProcess.StartInfo = New ProcessStartInfo(szServerPath)
                        '           oProcess.Start()
                        '           oParent.CloseIfNoShift()
                        '       End Using
                        '    End If
                    End If
                End If
            Catch
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

        Private Sub openCodeFiletoolStripMenuItem_DropDownOpening(sender As Object, e As EventArgs) Handles openCodeFiletoolStripMenuItem.DropDownOpening
            Dim oCursor As Cursor = Cursor.Current
            Try
                Cursor.Current = Cursors.WaitCursor
                Dim oParent As frmMain = ParentForm

                If (Not oParent.IsSearchTFSTabSelected) Or (lstSearchResults.SelectedItems.Count <> 1) Then Exit Sub

                Dim oChildMenuItem As ToolStripMenuItem = DirectCast(sender, ToolStripMenuItem)
                oChildMenuItem.DropDownItems.Clear()

                Dim szServerPath As String
                If (oChildMenuItem.Equals(openCodeFiletoolStripMenuItem)) Then
                    szServerPath = lstSearchResults.SelectedItems(0).SubItems(CInt(ProjectsColumnPosition.ItemPath)).Text
                Else
                    szServerPath = oChildMenuItem.Tag.ToString()
                End If

                If (String.IsNullOrWhiteSpace(szServerPath)) Then Return

                Dim oProject As TFSProject = cbProjects.SelectedItem
                Dim clcChildItems As List(Of TFSItem) = TfsApi.GetChildItems(GetCollection(), oProject, TFSItemType.Folder, szServerPath)

                Dim oFilterList As List(Of String) = Helper.GetCodeFileExtensions(Helper.ProjectType.VisualStudio)

                If (oFilterList.Count > 0) Then clcChildItems.AddRange(TfsApi.GetChildItems(GetCollection(), oProject, TFSItemType.File, szServerPath))

                For Each oChildItem As TFSItem In clcChildItems
                    If (oChildItem.ItemType = TFSItemType.File) Then
                        Dim szExtension As String = Path.GetExtension(oChildItem.ServerPath).TrimStart("."c)

                        If (Not oFilterList.Contains(szExtension.ToUpper())) Then Continue For

                        Dim iIndex As Integer = - 1
                        Try
                            iIndex = GetIconIndex(szExtension)
                        Catch
                            ' If we have problem getting the icon, we'd rather just show it without one than not at all
                        End Try

                        Dim oNewChild As ToolStripMenuItem
                        If (iIndex >= 0) Then
                            oNewChild = New ToolStripMenuItem(oChildItem.Name, m_oIconImageList.Images(iIndex))
                        Else
                            oNewChild = New ToolStripMenuItem(oChildItem.Name)
                        End If
                        AddHandler oNewChild.MouseDown, AddressOf openCodeFiletoolStripMenuItem_MouseDown
                        oNewChild.Tag = oChildItem.ServerPath
                        oChildMenuItem.DropDownItems.Add(oNewChild)
                    Else
                        Dim oNewChild As New ToolStripMenuItem(oChildItem.Name, openContainingDirectoryToolStripMenuItem.Image)
                        AddHandler oNewChild.DropDownOpening, AddressOf openCodeFiletoolStripMenuItem_DropDownOpening
                        AddHandler oNewChild.MouseDown, AddressOf openCodeFiletoolStripMenuItem_MouseDown
                        oNewChild.Tag = oChildItem.ServerPath

                        ' For now assume that each folder has a child under it
                        Dim oPlaceHolder As New ToolStripMenuItem("PlaceHolder")
                        oNewChild.DropDownItems.Add(oPlaceHolder)

                        oChildMenuItem.DropDownItems.Add(oNewChild)
                    End If
                Next
            Catch oExp As Exception
                Cursor.Current = oCursor
                Helper.DisplayException(oExp, Me, "Exception Loading Code Subfiles")
            Finally
                Cursor.Current = oCursor
            End Try
        End Sub

#End Region

        Private Sub lstSearchResults_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles lstSearchResults.ColumnClick
            Try
                If e.Column = m_iCurrentColumn Then
                    m_bAscending = Not m_bAscending
                Else
                    m_bAscending = True
                End If

                ' Set the ListViewItemSorter property to a new ListViewItemComparer object.
                Dim eCompareType As ListViewItemComparer.CompareType
                'If e.Column = CInt(ProjectsColumnPosition. ) Then
                '    eCompareType = ListViewItemComparer.CompareType.Int
                'Else
                eCompareType = ListViewItemComparer.CompareType.String
                'End If
                lstSearchResults.ListViewItemSorter = New ListViewItemComparer(e.Column, m_bAscending, eCompareType)
                ' Call the sort method to manually sort.
                lstSearchResults.Sort()

                m_iCurrentColumn = e.Column
            Catch
            End Try
        End Sub

        Private Sub lstSearchResults_DoubleClick(sender As Object, e As EventArgs) Handles lstSearchResults.DoubleClick
            Try
                OpenProjectsToolStripMenuItem_Click(sender, e)
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Opening Selected Project(s)")
            End Try
        End Sub

        Private Sub pbRecentConfiguration_Click(sender As Object, e As EventArgs) Handles pbRecentConfiguration.Click
            Try
                Using ofrmSearchTFSConfiguration As New frmSearchTFSConfiguration()
                    ofrmSearchTFSConfiguration.ShowDialog(Me)
                End Using
            Catch oExp As Exception
                Helper.DisplayException(oExp, Me, "Exception Setting Search TFS Configuration")
            End Try
        End Sub
    End Class
End Namespace